using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Shapes;
using Avalonia.Input;
using Avalonia.Media;
using Avalonia.Media.TextFormatting;

namespace Digitalmes.AvaloniaUI.Behaviors.DragAndDrop;

/// <summary>
/// 可拖动的矩形。
/// </summary>
public class DraggableRectangle : DraggableControl
{
    private Point _startPoint; // 矩形的起点
    private readonly Canvas _canvas; // 画布
    private bool _isDragging; // 是否正在拖动
    private bool _canDraggable = true; // 是否可以拖动

    /// <summary>
    /// 填充属性。
    /// </summary>
    public static readonly StyledProperty<IBrush?> FillProperty =
        AvaloniaProperty.Register<DraggableRectangle, IBrush?>(nameof(Fill), Brushes.Red);

    /// <summary>
    /// 笔划属性。
    /// </summary>
    public static readonly StyledProperty<IBrush?> StrokeProperty =
        AvaloniaProperty.Register<DraggableRectangle, IBrush?>(nameof(Stroke), Brushes.Red);

    /// <summary>
    /// 文本属性。
    /// </summary>
    public static readonly StyledProperty<string?> TextProperty =
       AvaloniaProperty.Register<DraggableRectangle, string?>(nameof(Text), string.Empty);

    /// <summary>
    /// 文本字体大小属性。
    /// </summary>
    public static readonly StyledProperty<double> FontSizeProperty =
        AvaloniaProperty.Register<DraggableControl, double>(nameof(FontSize), 16.0);

    /// <summary>
    /// 获取或设置填充。
    /// </summary>
    public IBrush? Fill
    {
        get => GetValue(FillProperty);
        set => SetValue(FillProperty, value);
    }

    /// <summary>
    /// 获取或设置笔划（边框）。
    /// </summary>
    public IBrush? Stroke
    {
        get => GetValue(StrokeProperty);
        set => SetValue(StrokeProperty, value);
    }

    /// <summary>
    /// 获取或设置文本。
    /// </summary>
    public string? Text
    {
        get => GetValue(TextProperty);
        set => SetValue(TextProperty, value);
    }

    /// <summary>
    /// 获取或设置文本字体大小。
    /// </summary>
    public double FontSize
    {
        get => GetValue(FontSizeProperty);
        set => SetValue(FontSizeProperty, value);
    }

    public DraggableRectangle(Point origin, Canvas canvas)
    {
        _startPoint = origin;
        _canvas = canvas;

        // 默认大小
        Width = 92;
        Height = 48;

        // 检查图形是否都在 Canvas 内
        var canvasRect = _canvas.Bounds;
        Canvas.SetLeft(this, Math.Clamp(origin.X, 0, canvasRect.Width - Width));
        Canvas.SetTop(this, Math.Clamp(origin.Y, 0, canvasRect.Height - Height));

        PointerPressed += OnPointerPressed;
    }

    /// <summary>
    /// 启用菜单。
    /// </summary>
    public void EnableContextMenu()
    {
        ContextMenu = new ContextMenu();

        // 菜单删除项
        var deleteMenuItem = new MenuItem { Header = "删除" };
        deleteMenuItem.Click += (s, e) =>
        {
            _canvas.Children.Remove(this);
        };

        ContextMenu.Items.Add(deleteMenuItem);
    }

    protected void OnPointerPressed(object? sender, PointerPressedEventArgs e)
    {
        if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
        {
            // 双击事件，编辑文本。
            if (e.ClickCount == 2)
            {
                ShowTextEditor();
            }
            else
            {
                if (_canDraggable)
                {
                    _isDragging = true;
                    _startPoint = e.GetPosition(_canvas);

                    e.Handled = true;
                }
            }
        }
    }

    protected override void OnPointerMoved(PointerEventArgs e)
    {
        if (!_isDragging)
        {
            return;
        }

        base.OnPointerMoved(e);

        var currentPoint = e.GetPosition(_canvas); // 鼠标在当前 Canvas 中的相对位置点; e.GetPosition(this) 为鼠标在当前控件中的相对位置点

        // 计算边界，反正拖拽时超出 Canvas
        var canvasRect = _canvas.Bounds;
        var delta = currentPoint - _startPoint;
        var x = Math.Clamp(Canvas.GetLeft(this) + delta.X, 0, canvasRect.Width - Width);
        var y = Math.Clamp(Canvas.GetTop(this) + delta.Y, 0, canvasRect.Height - Height);
        Canvas.SetLeft(this, x);
        Canvas.SetTop(this, y);
        _startPoint = currentPoint;
    }

    protected override void OnPointerReleased(PointerReleasedEventArgs e)
    {
        base.OnPointerReleased(e);

        _isDragging = false;
    }

    public override void Render(DrawingContext context)
    {
        base.Render(context);

        // 绘制矩形
        var pen = new Pen(Stroke, 2); // 边框
        context.DrawRectangle(Fill, pen, new Rect(0, 0, Bounds.Width, Bounds.Height), 5, 5);

        // 绘制文本
        if (!string.IsNullOrEmpty(Text))
        {
            var textLayout = new TextLayout(
                Text,
                new Typeface(FontFamily.Default),
                FontSize,
                Brushes.White,
                textAlignment: TextAlignment.Center,
                textWrapping: TextWrapping.Wrap);

            var textPosition = new Point((Bounds.Width - textLayout.Width) / 2, (Bounds.Height - textLayout.Height) / 2);
            textLayout.Draw(context, textPosition);
        }
    }

    protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
    {
        base.OnPropertyChanged(change);

        switch (change.Property.Name)
        {
            case nameof(Fill):
            case nameof(Stroke):
            case nameof(Text):
            case nameof(FontSize):
                InvalidateVisual(); // 重绘（标记元素的视觉树为无效）
                break;
            default:
                break;
        }
    }

    /// <summary>
    /// 显示文本编辑器。
    /// </summary>
    private void ShowTextEditor()
    {
        var textBox = new TextBox
        {
            Text = Text,
            Width = Bounds.Width,
            Height = Bounds.Height,
            Background = Brushes.Orange,
            Foreground = Brushes.White,
            TextAlignment = TextAlignment.Center,
            VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center,
        };

        // 按下回车键，保存文本
        textBox.KeyDown += (sender, args) =>
        {
            if (args.Key is Key.Enter)
            {
                Text = textBox.Text;
                _canvas.Children.Remove(textBox);
                _canDraggable = true;
            }
            else if (args.Key is Key.Escape)
            {
                _canvas.Children.Remove(textBox);
                _canDraggable = true;
            }
        };

        Canvas.SetLeft(textBox, Canvas.GetLeft(this));
        Canvas.SetTop(textBox, Canvas.GetTop(this));
        _canvas.Children.Add(textBox);
        textBox.Focus();
        _canDraggable = false;
    }
}
